
package addroleservice;

import java.io.*;
import java.sql.*;

import javax.xml.namespace.QName;
import javax.xml.rpc.Call;
import javax.xml.rpc.ParameterMode;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceFactory;


public class AddRoleImpl implements AddRoleIF {
    
//	define DII method
	private static String qnameService = "VoteService";
    private static String qnamePort = "VoteIF";
    private static String BODY_NAMESPACE_VALUE = "urn:Foo";
    private static String ENCODING_STYLE_PROPERTY = "javax.xml.rpc.encodingstyle.namespace.uri";
    private static String NS_XSD = "http://www.w3.org/2001/XMLSchema";
    private static String URI_ENCODING = "http://schemas.xmlsoap.org/soap/encoding/";
    
    //voting result
    boolean result;

	/**
	 * A method constructing DII 
	 * @param addr					Address of partner company that provides vote service.
	 * @param roleName				Name of the target role.
	 * @param EPCClass				EPCClass value associated with the target role.
	 * @param comId					Applicant company's id.
	 * @param serviceProviderComId	Id of voting partner company.
	 * @return						true if voting partner supports for role grant.
	 */
	public boolean invokeUpdateService(String addr, String roleName){
				//construct complete endPointAddress
		   		String endPointAddr = addr+"AddRoleInHierarchy/update";
		        System.out.println("Endpoint address = " + endPointAddr);

		        try {
		        	//create call
		            ServiceFactory factory = ServiceFactory.newInstance();
		            Service service = factory.createService(new QName(qnameService));
		            Call call = service.createCall(new QName(qnamePort));

		            call.setTargetEndpointAddress(endPointAddr);
		            call.setProperty(Call.SOAPACTION_USE_PROPERTY, new Boolean(true));
		            call.setProperty(Call.SOAPACTION_URI_PROPERTY, "");
		            call.setProperty(ENCODING_STYLE_PROPERTY, URI_ENCODING);

		            
		            QName QNAME_TYPE_STRING = new QName(NS_XSD, "string");
		            QName QNAME_TYPE_BOOLEAN = new QName(NS_XSD, "boolean");
		            //set return type
		            call.setReturnType(QNAME_TYPE_BOOLEAN);

//		            set access point method for service
		            call.setOperationName(new QName(BODY_NAMESPACE_VALUE, "update"));
//		            //set parameters
		            call.addParameter("String_1", QNAME_TYPE_STRING, ParameterMode.IN);

		            
		            String[] params = {roleName};

		            //invoke the target method with constructed parameter(s)
		            System.out.println("Accessing service on: "+endPointAddr+"...");
		            result = (Boolean) call.invoke(params);
		            System.out.println("Update result from "+endPointAddr+"is "+result);


		        } catch (Exception ex) {
		            ex.printStackTrace();
		        }
		        return result;
		    }


	
	
	/* (non-Javadoc)
	 * @see addroleservice.AddRoleIF#addRole(java.lang.String)
	 */
	public boolean addRole(String roleName)
	{
	
		
		//define the driver to use 
	      String driver = "org.apache.derby.jdbc.ClientDriver";
	    //the database name  
	      String dbName="RSSdb";
	      System.out.println("the dbName is: "+dbName);
	    //define the Derby connection URL to use 
	      String connectionURL = "jdbc:derby://localhost:1527/" + dbName;
	      System.out.println("the connectionURL is: "+connectionURL);
	    
	    
	      Connection conn = null;
	      Statement s;
	      Statement s1;
	      ResultSet rs;
	      ResultSet rs1;
	      boolean result=false;
	      
	    //load derby driver
	      try{
	          Class.forName(driver); 
	          System.out.println(driver + " loaded. ");
	      } catch(java.lang.ClassNotFoundException e)     {
	          System.err.print("ClassNotFoundException: ");
	          System.err.println(e.getMessage());
	          System.out.println("\n    >>> Please check your CLASSPATH variable   <<<\n");
	      }
	      
		
		try{
			conn = DriverManager.getConnection(connectionURL);
			System.out.println("Connected to database " + dbName);
			
			s=conn.createStatement();
			
			//construct sql: get record set with target roleName
			String sqlGetRole = "SELECT * FROM roleDictionary WHERE roleName='"+roleName+"'";
		
			rs = s.executeQuery(sqlGetRole);
			
			//if there is a role has the same name as target role, return false
			if(rs.next()){
//				close connection
				conn.close();
				System.out.println("Role exists!");
				return false;	
			}
			
			//look for all participants in the traceability network
			String sqlGetAllPar = "SELECT * FROM company";
			s1 = conn.createStatement();
			rs1=s1.executeQuery(sqlGetAllPar);
			
			boolean empty=true;
			
			while(rs1.next()){
				empty=false;
				String address =rs1.getString("address");
				//update all participants' role hierarchies
				invokeUpdateService(address, roleName);
			}
			
			if(empty){
//				close connection
				conn.close();
				System.out.println("There is no participant in the traceability network!");
				return false;
			}
				
			//add role into Role Dictionary
			result=hookAddRoleIntoRoleDictionary(roleName);
			
			//close connection
			conn.close();
			System.out.println("Role: " +roleName +" has been added into Role Dictionary!");
			return true;
		}catch(Exception e){
			e.printStackTrace();
		}

		return result;
	}
	
	/**Programmers can use this hook method to add the target role into the role dictionary according to their view of the target role
	 * @param roleName	Name of the target role.
	 * @return			true if target role has been added.
	 */
	private boolean hookAddRoleIntoRoleDictionary(String roleName){
		return true;
	}
}
